﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace libManagedMessageSystem
{
    public class MessageSystem:IDisposable
    {
        class ListenProxy
        {
            private MessageSystem.OnAccept m_pa = null;
            private GCHandle               m_h;

            public void Listen(IntPtr ms,String ip,UInt16 port,MessageSystem.OnAccept a)
            {
                m_pa = a;

                libMessageSystemApi.OnAccept la = new libMessageSystemApi.OnAccept(this.OnAccept);
                m_h = GCHandle.Alloc(la);

                libMessageSystemApi.MessageSystemListenLocalSystem(ms, ip, port,la, IntPtr.Zero);
            }

            private void OnAccept(IntPtr mc, IntPtr ud)
            {
                MessageChannel mmc = new MessageChannel(mc);
                m_pa(mmc);
            }
        }

        class ConnectProxy
        {
            private MessageSystem.OnConnectSuccess m_ps;
            private MessageSystem.OnConnectFailed  m_pf;
            private GCHandle                       m_h1;
            private GCHandle                       m_h2;

            public void Connect(IntPtr ms,String ip,UInt16 port,MessageSystem.OnConnectSuccess s,MessageSystem.OnConnectFailed f)
            {
                m_ps = s;
                m_pf = f;

                libMessageSystemApi.OnConnectSuccess ls = new libMessageSystemApi.OnConnectSuccess(OnConnectSuccess);
                m_h1 = GCHandle.Alloc(ls);
                libMessageSystemApi.OnConnectFailed lf = new libMessageSystemApi.OnConnectFailed(OnConnectFailed);
                m_h2 = GCHandle.Alloc(lf);

                libMessageSystemApi.MessageSystemConnectRemoteSystem(ms, ip, port, ls, lf, IntPtr.Zero);
            }

            private void OnConnectSuccess(IntPtr mc, IntPtr ud)
            {
                MessageChannel mmc = new MessageChannel(mc);
                m_ps(mmc);

                m_h1.Free();
                m_h2.Free();
            }

            private void OnConnectFailed(Int32 ec, IntPtr ud)
            {
                m_pf(ec);

                m_h1.Free();
                m_h2.Free();
            }
        }

        public delegate void OnAccept(MessageChannel mc);
        public delegate void OnConnectSuccess(MessageChannel mc);
        public delegate void OnConnectFailed(Int32 ec);

        internal static NetStream Ns;        
        private  static byte[]    NsBuffer;        
        internal static List<MessageChannel> Channels;       

        public MessageSystem()
        {
            Channels = new List<MessageChannel>();
            Ns = new NetStream();

            NsBuffer = new byte[UInt16.MaxValue];
            GCHandle h = GCHandle.Alloc(NsBuffer, GCHandleType.Pinned);
            unsafe
            {
                Ns.Reset((byte*)h.AddrOfPinnedObject().ToPointer(), (UInt32)NsBuffer.Length);
            }           

            m_pMessageSystem = libMessageSystemApi.MessageSystemCreate();
        }

        public void SetOption(MessageSystemOption op,UInt32 nValue)
        {
            libMessageSystemApi.MessageSystemSetOption(m_pMessageSystem, (uint)op, nValue);
        }

        public void ListenLocalSystem(String ip, UInt16 port, OnAccept a)
        {
            ListenProxy proxy = new ListenProxy();
            proxy.Listen(m_pMessageSystem, ip, port, a);
        }

        public void ConnectRemoteSystem(String ip, UInt16 port, OnConnectSuccess s, OnConnectFailed f)
        {
            ConnectProxy proxy = new ConnectProxy();
            proxy.Connect(m_pMessageSystem, ip, port, s, f);
        }

        public virtual void Dispose()
        {
            if ( m_pMessageSystem != IntPtr.Zero )
            {
                libMessageSystemApi.MessageSystemDestroy(m_pMessageSystem);
                m_pMessageSystem = IntPtr.Zero;   
            }
        }

        public void Poll(UInt32 wait)
        {
            libMessageSystemApi.MessageSystemPoll(m_pMessageSystem, wait);
        }

        private IntPtr m_pMessageSystem;
    }
}
